package cn.swust.designpatternlearningplatform.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.swust.designpatternlearningplatform.listener.TopicExcelDataListener;
import cn.swust.designpatternlearningplatform.common.Result.PageInfo;
import cn.swust.designpatternlearningplatform.common.exception.CustomException;
import cn.swust.designpatternlearningplatform.common.utils.AuthUserContext;
import cn.swust.designpatternlearningplatform.common.utils.OrikaMapperUtil;
import cn.swust.designpatternlearningplatform.common.utils.SimilarityUtil;
import cn.swust.designpatternlearningplatform.common.utils.TopicHelpContext;
import cn.swust.designpatternlearningplatform.dao.*;
import cn.swust.designpatternlearningplatform.domain.bo.*;
import cn.swust.designpatternlearningplatform.domain.dto.*;
import cn.swust.designpatternlearningplatform.domain.entity.*;
import cn.swust.designpatternlearningplatform.domain.enums.RoleEnum;
import cn.swust.designpatternlearningplatform.domain.enums.TopicRecordEnum;
import cn.swust.designpatternlearningplatform.domain.enums.TopicTypeEnum;
import cn.swust.designpatternlearningplatform.domain.enums.TopicUpdateTypeEnum;
import cn.swust.designpatternlearningplatform.domain.vo.TopicExcelVo;
import cn.swust.designpatternlearningplatform.domain.vo.TopicVo;
import cn.swust.designpatternlearningplatform.service.TopicCollectService;
import cn.swust.designpatternlearningplatform.service.TopicService;
import com.alibaba.excel.EasyExcel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

@Service
@Slf4j
public class TopicServiceImpl implements TopicService {
    @Resource
    private TopicDao topicDao;
    @Resource
    private TopicOptionDao topicOptionDao;
    @Resource
    private TopicKnowledgeCorrelationDao topicKnowledgeCorrelationDao;
    @Resource
    private DailyExerciseDao dailyExerciseDao;
    @Resource
    private TopicIndicatorsDao topicIndicatorsDao;
    @Resource
    private TopicKnowledgePointDao topicKnowledgePointDao;
    @Resource
    private TopicCollectService topicCollectService;
    @Resource
    private TopicSimilarDao topicSimilarDao;

    /**
     * 获取题目
     *
     * @param topicId
     * @return java.util.List<cn.swust.designpatternlearningplatform.domain.entity.TopicOption>
     * @author Tang
     * @date 2023/5/13 20:56
     **/
    @Override
    public TopicDto selectTopicById(Integer topicId) {
        Topic topic = topicDao.selectTopicById(topicId);
        return Topic2TopicDto(topic, null);
    }

    /**
     * 获取与知识点相关联的题目
     *
     * @param pointId
     * @return java.util.List<cn.swust.designpatternlearningplatform.domain.dto.TopicDto>
     * @author Tang
     * @date 2023/7/24 10:48
     **/
    @Override
    public List<TopicDto> selectTopicByPointId(Integer pointId) {
        List<TopicDto> topicDtos = TopicHelpContext.get(pointId);
        if (topicDtos != null) {
            return topicDtos;
        }
        Set<Integer> collect = new HashSet<>(topicKnowledgeCorrelationDao.selectPointLinkedWithTopic(pointId));
        if (collect.size() == 0) {
            return new ArrayList<>();
        }
        List<TopicDto> topicDtos1 = topic2sDtoList(collect, new String[0]);
        if (TopicHelpContext.get() != null) {
            TopicHelpContext.set(pointId, topicDtos1);
        }
        return topicDtos1;
    }

    /**
     * 获取题目的选项
     *
     * @param topicBo
     * @return java.util.List<cn.swust.designpatternlearningplatform.domain.entity.TopicOption>
     * @author Tang
     * @date 2023/5/13 20:56
     **/
    @Override
    public List<TopicOption> getOptionsOfTopic(TopicBo topicBo) {
        return topicOptionDao.getOptionsOfTopic(topicBo.getTopicId());
    }

    /**
     * 添加题目（基本信息，题目选项信息，知识点信息）
     *
     * @param topicBo
     * @param topicKpointBo
     * @param topicOptionsBo
     * @return void
     * @author Tang
     * @date 2023/5/13 20:56
     **/
    @Override
    public void addTopic(TopicBo topicBo, TopicKpointBo topicKpointBo, TopicOptionsBo topicOptionsBo) {
        try {
            //添加题目基本信息
            Topic topic = new Topic();
            BeanUtils.copyProperties(topicBo, topic);
            topicDao.insertOrUpdateTopic(topic);
            //获取题目id
            topicKpointBo.setTopicId(topic.getTopicId());
            topicOptionsBo.setTopicId(topic.getTopicId());
            //添加知识点
            if (topicKpointBo.getPointIds() != null) {
                List<TopicKnowledgeCorrelation> pointLink = topicKpointBo.getPointIds().stream().map(i -> {
                    TopicKnowledgeCorrelation topicKnowledgeCorrelation = new TopicKnowledgeCorrelation();
                    topicKnowledgeCorrelation.setTopicId(topicKpointBo.getTopicId());
                    topicKnowledgeCorrelation.setPointId(i);
                    return topicKnowledgeCorrelation;
                }).collect(Collectors.toList());
                topicKnowledgeCorrelationDao.insertBatch(pointLink);
                calculateSimilarity(topic, pointLink);
            }
            //添加选项
            TopicOption topicOption = new TopicOption();
            topicOption.setTopicId(topicOptionsBo.getTopicId());
            topicOptionsBo.getTopicOptions().forEach(i -> {
                BeanUtils.copyProperties(i, topicOption);
                topicOptionDao.addOption(topicOption);
            });

        } catch (BeansException e) {
            throw new CustomException("添加失败");
        }
    }

    @Async
    protected void calculateSimilarity(Topic topic, List<TopicKnowledgeCorrelation> pointLink) {
        //相似度判断
        for (TopicKnowledgeCorrelation topicKnowledgeCorrelation : pointLink) {
            List<TopicSimilar> need = new ArrayList<>();
            List<TopicDto> topicDtos = selectTopicByPointId(topicKnowledgeCorrelation.getPointId());
            for (TopicDto topicDto : topicDtos) {
                double similarity = SimilarityUtil.getSimilarity(topic.getTopicContent(), topicDto.getTopicContent());
                if (similarity > 0.70) {
                    TopicSimilar topicSimilar = new TopicSimilar();
                    topicSimilar.setTopicidSrc(topic.getTopicId());
                    topicSimilar.setTopicidTarget(topicDto.getTopicId());
                    topicSimilar.setSimilar(new BigDecimal(similarity).setScale(3, RoundingMode.HALF_UP));
                    need.add(topicSimilar);
                }
            }
            if (need.size() != 0) {
                topicSimilarDao.insertBatch(need);
            }
        }
    }

    /**
     * 通过excel批量添加题目
     *
     * @param file
     * @return void
     * @author Tang
     * @date 2023/5/25 12:27
     **/
    @Override
    public List<TopicVo> readTopicByExcel(MultipartFile file) throws IOException {
        //表格数据读取监听器
        TopicExcelDataListener excelDataListener = new TopicExcelDataListener();
        EasyExcel.read(file.getInputStream(), TopicExcelVo.class, excelDataListener).sheet().doRead();
        return excelDataListener.getRight();
    }

    @Override
    public void addTopicByExcel(MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null) {
            throw new CustomException("文件名不能为空");
        }
        try {
            String pointName = originalFilename.split("\\.")[0];
            Integer knowledgeIdByName = topicKnowledgePointDao.selectPointIdByContent(pointName);
            List<TopicVo> topicVos = readTopicByExcel(file);
            topicVos.forEach(i -> i.setPointId(Collections.singletonList(knowledgeIdByName)));
            Vector<TopicVo> currentTopic = new Vector<>(topicVos);
            List<Integer> error = new ArrayList<>();
            addTopicSync(currentTopic, error);
            if (error.size() != 0) {
                throw new CustomException(error.toString());
            }
        } catch (IOException e) {
            throw new CustomException("上传失败");
        }
    }

    /**
     * 更新题目指数
     *
     * @param topicBo
     * @return void
     * @author Tang
     * @date 2023/5/13 20:57
     **/
    @Override
    public void updateTopicIndicatorsDifficulty(TopicBo topicBo) {
        DailyExerciseBo dailyExerciseBo = new DailyExerciseBo();
        BeanUtils.copyProperties(topicBo, dailyExerciseBo);
        List<DailyExerciseDto> dailyExerciseDto = dailyExerciseDao.selectByTopicId(dailyExerciseBo);
        //统计正确的人数
        long right = 0;
        for (DailyExerciseDto exerciseDto : dailyExerciseDto) {
            if (exerciseDto.getIsRight().equals(TopicRecordEnum.RIGHT.getIsRight())) {
                right++;
            }
        }
        BigDecimal wrongDegree = BigDecimal.valueOf(dailyExerciseDto.size() - right)
                .divide(BigDecimal.valueOf(dailyExerciseDto.size()), 4, RoundingMode.HALF_UP);
        TopicIndicators topicIndicators = new TopicIndicators();
        topicIndicators.setTopicId(topicBo.getTopicId());
        topicIndicators.setDegreeOfDifficulty(wrongDegree);
        topicIndicatorsDao.insertOrUpdateTopicIndicatorsDifficulty(topicIndicators);
    }

    /**
     * 分页查询题目
     *
     * @param pageInfo
     * @param ignore
     * @return cn.swust.designpatternlearningplatform.common.Result.PageInfo<cn.swust.designpatternlearningplatform.domain.dto.TopicDto>
     * @author Tang
     * @date 2023/7/10 13:25
     **/
    @Override
    public PageInfo<TopicDto> selectByPage(PageInfo<TopicDto> pageInfo, Integer pointId, String[] ignore) {

        Integer total = 0;
        List<Integer> topicIds = new ArrayList<>();

        if (pointId == null) {
            total = topicDao.selectTopicByPageAllNum();
            topicIds = topicDao.selectTopicIdsByPointIds(null, (pageInfo.getCurrentPage() - 1) * pageInfo.getPageSize(),
                    pageInfo.getPageSize());
        } else {
            //查询知识点及其子知识点
            List<Integer> pointIds = new ArrayList<>();
            Queue<Integer> pointQue = new ArrayDeque<>();
            pointQue.add(pointId);
            pointIds.add(pointId);
            while (!pointQue.isEmpty()) {
                Integer poll = pointQue.poll();
                Set<Integer> pointIdsSet = topicKnowledgePointDao.selectKnowledgePointSonId(poll).stream().map(KnowledgePoint::getPointId).collect(Collectors.toSet());
                if (pointIdsSet.isEmpty()) {
                    continue;
                }
                pointIds.addAll(pointIdsSet);
            }
            //分页查询
            if (!pointIds.isEmpty()) {
                total = topicKnowledgeCorrelationDao.selectPointLinkedWithTopicNumBatch(pointIds);
                topicIds = topicDao.selectTopicIdsByPointIds(pointIds, (pageInfo.getCurrentPage() - 1) * pageInfo.getPageSize(),
                        pageInfo.getPageSize());
            }
        }
        //获取题目id
        Set<Integer> tidList = new HashSet<>(topicIds);
        //topic转topicDto
        List<TopicDto> topicDtoList = topic2sDtoList(tidList);

        pageInfo.setTotal(total);
        pageInfo.setData(topicDtoList);

        return pageInfo;
    }

    /**
     * 更新题目
     *
     * @param topicBo
     * @param topicKpointBo
     * @param topicOptionsBo
     * @return void
     * @author Tang
     * @date 2023/7/22 10:34
     **/
    @Override
    public void updateTopic(TopicBo topicBo, TopicKpointBo topicKpointBo, TopicOptionsBo topicOptionsBo) {
        try {
            Integer topicId = topicBo.getTopicId();
            //添加题目基本信息
            Topic topic = new Topic();
            BeanUtils.copyProperties(topicBo, topic);
            topicDao.update(topic);
            //获取题目id
            topicKpointBo.setTopicId(topicId);
            topicOptionsBo.setTopicId(topicId);
            //修改知识点
            //查询已有的知识点
            List<Integer> ids = topicKpointBo.getPointIds();
            //list深度拷贝
            List<Integer> existIds = new ArrayList<>(ids);
            Collections.copy(existIds, ids);
            List<Integer> pointIds = topicKnowledgeCorrelationDao.selectTopicLinkedWithPoint(topicId);
            //添加新增的知识点
            existIds.removeAll(pointIds);
            TopicKnowledgeCorrelation topicKnowledgeCorrelation = new TopicKnowledgeCorrelation();
            topicKnowledgeCorrelation.setTopicId(topicId);
            existIds.forEach(i -> {
                topicKnowledgeCorrelation.setPointId(i);
                topicKnowledgeCorrelationDao.insertTopicKnowledgeCorrelation(topicKnowledgeCorrelation);
            });
            //删除在修改中去掉的知识点
            pointIds.removeAll(ids);
            pointIds.forEach(i -> {
                topicKnowledgeCorrelationDao.deleteById(topicId, i);
            });

            //添加选项
            topicOptionDao.deleteByTopicId(topicId);
            TopicOption topicOption = new TopicOption();
            topicOption.setTopicId(topicId);
            topicOptionsBo.getTopicOptions().forEach(i -> {
                BeanUtils.copyProperties(i, topicOption);
                topicOptionDao.addOption(topicOption);
            });
        } catch (BeansException e) {
            throw new CustomException("更新失败");
        }
    }

    /**
     * 批量删除
     *
     * @param topicIds
     * @return void
     * @author Tang
     * @date 2023/7/22 11:36
     **/
    @Override
    public void batchDelete(List<Integer> topicIds) {
        try {
            for (Integer topicId : topicIds) {
                topicDao.deleteByTopicId(topicId);
                topicKnowledgeCorrelationDao.deleteAllByTopicId(topicId);
                topicOptionDao.deleteByTopicId(topicId);
            }
        } catch (Exception e) {
            throw new CustomException("删除失败");
        }
    }

    /**
     * 根据题目id批量查询题目信息
     *
     * @param topicIds
     * @return java.util.List<cn.swust.designpatternlearningplatform.domain.dto.TopicDto>
     * @author Tang
     * @date 2023/10/3 16:10
     **/
    @Override
    public List<TopicDto> getTopicByTopicIds(List<Integer> topicIds) {
        return topic2sDtoList(topicIds);
    }

    /**
     * 根据学号查询做过的题目
     *
     * @param studentNumber
     * @return
     */
    @Override
    public PageInfo<TopicDto> getTopicByStudentNumber(String studentNumber, Integer pointId, Integer currentPage, Integer size) {
        if (currentPage == null) {
            currentPage = 1;
        }
        if (size == null) {
            size = 5;
        }
        Integer total = dailyExerciseDao.totalOfStudent(studentNumber);
        List<Integer> topicIds = dailyExerciseDao.recordOfStudent(studentNumber, pointId, (currentPage - 1) * size, size);
        List<TopicDto> topicDtos = topic2sDtoList(topicIds);
        return new PageInfo<>(total,currentPage,size,topicDtos);
    }

    /**
     * 查询题目信息
     *
     * @param topicIds
     * @return java.util.List<cn.swust.designpatternlearningplatform.domain.dto.TopicDto>
     * @author Tang
     * @date 2023/10/12 17:32
     **/
    private List<TopicDto> topic2sDtoList(Collection<Integer> topicIds) {
        //查询带知识点信息的题目信息
        Map<Integer, TopicDto> topicDtoMap = topicDao
                .selectTopicWithPointInfo(topicIds).stream().collect(Collectors.toMap(TopicDto::getTopicId, i -> i));
        //查询题目选项
        topicOptionDao.selectTopicOptionsByTopicIds(topicIds).forEach(i -> {
            Integer topicId = i.getTopicId();
            if (topicId == null) {
                return;
            }
            //回填选项
            TopicDto topicDto = topicDtoMap.get(topicId);
            topicDto.setTopicOptionDtos(i.getTopicOptionDtos());
        });
        return new ArrayList<>(topicDtoMap.values());
    }

    /**
     * 多了知识点、选项、是否收藏
     */
    public List<TopicDto> topic2sDtoList(Collection<Integer> topicIds, String[] ignore) {
        TimeInterval timer = DateUtil.timer();
        //1.查询题目
        List<Topic> topics = topicDao.getTopicsByIds(topicIds);
        //1.先整出topicDto，加个学生判断
        List<TopicDto> topicDtoList;
        TokenInfoBo tokenInfoBo = AuthUserContext.get();
        if (RoleEnum.STUDENT.getRoleName().equals(tokenInfoBo.getRole())) {
            topicDtoList = OrikaMapperUtil.INSTANCE.mapAsList(TopicDto.class, topics, ignore);
        } else {
            topicDtoList = OrikaMapperUtil.INSTANCE.mapAsList(TopicDto.class, topics);
        }
        log.error("{}", timer.intervalRestart());
        Map<Integer, TopicDto> topicDtoMap = topicDtoList.stream().collect(Collectors.toMap(TopicDto::getTopicId, id -> id));
        //2.知识点数据准备
        //2.1 获取全部关联的知识点
        List<TopicKnowledgeCorrelation> topicKnowledgeCorrelations = topicKnowledgeCorrelationDao.selectPointsByTopicIds(topicIds);
        //2.2 根据题目id，将知识点id进行划分
        Map<Integer, Set<Integer>> topicIdWithPointIdMap = topicKnowledgeCorrelations.stream().collect(Collectors.groupingBy(TopicKnowledgeCorrelation::getTopicId, Collectors.mapping(TopicKnowledgeCorrelation::getPointId, Collectors.toSet())));
        //2.3 查询所有知识点详情（全部查出来，省的重复查询），注：此处可以使用缓存进行优化，就不用查询详情了
        Set<Integer> pointIds = topicKnowledgeCorrelations.stream().map(TopicKnowledgeCorrelation::getPointId).collect(Collectors.toSet());
        List<KnowledgePoint> knowledgePoints = topicKnowledgePointDao.selectByPointIds(pointIds);
        List<KnowledgePointDto> knowledgePointDtoList = OrikaMapperUtil.INSTANCE.mapAsList(KnowledgePointDto.class, knowledgePoints);
        //2.4 可以根据map查询
        Map<Integer, KnowledgePointDto> knowledgePointDtoMap = knowledgePointDtoList.stream().collect(Collectors.toMap(KnowledgePointDto::getPointId, kp -> kp));
        log.error("{}", timer.intervalRestart());
        //3 选项数据准备
        //3.1 查询出全部选项
        List<TopicOption> topicOptions = topicOptionDao.getByTopicIds(topicIds);
        List<TopicOptionDto> topicOptionDtos = OrikaMapperUtil.INSTANCE.mapAsList(TopicOptionDto.class, topicOptions);
        Map<Integer, List<TopicOptionDto>> topicOptionDtoMap = topicOptionDtos.stream()
                .collect(Collectors.groupingBy(TopicOptionDto::getTopicId));
        log.error("{}", timer.intervalRestart());
        //4 进行填充
        topicDtoList = topicDtoList.stream().peek(t -> {
            Integer tid = t.getTopicId();
            //4.1 填充知识点
            List<KnowledgePointDto> myKnowledgePoints = topicIdWithPointIdMap.getOrDefault(tid, new HashSet<>()).stream().map(knowledgePointDtoMap::get).collect(Collectors.toList());
            t.setPoints(myKnowledgePoints);
            //4.2 填充选项
            List<TopicOptionDto> optionDtos = topicOptionDtoMap.get(tid);
            t.setTopicOptionDtos(optionDtos);
        }).collect(Collectors.toList());

        //5.学生则填充收藏
        if (RoleEnum.STUDENT.getRoleName().equals(tokenInfoBo.getRole())) {

            //5.1 根据条件查询用户的收藏题目
            List<TopicUpdate> collects = topicCollectService.getCollectsByStuNumAndTopicIds(tokenInfoBo.getNumber(), topicIds, TopicUpdateTypeEnum.COLLECT.getTypeName());
            for (TopicUpdate collect : collects) {
                topicDtoMap.get(collect.getTopicId()).setIsCollect(Boolean.TRUE);
            }
            //5.2 根据条件查询用户的屏蔽题目
            List<TopicUpdate> shields = topicCollectService.getCollectsByStuNumAndTopicIds(tokenInfoBo.getNumber(), topicIds, TopicUpdateTypeEnum.SHIELD.getTypeName());
            for (TopicUpdate shield : shields) {
                topicDtoMap.get(shield.getTopicId()).setIsShield(Boolean.TRUE);
            }
        }
        log.error("{}", timer.intervalRestart());
        return topicDtoList;
    }

    private TopicDto Topic2TopicDto(Topic topic, String[] ignore) {
        TopicDto topicDto = new TopicDto();
        BeanUtils.copyProperties(topic, topicDto, ignore);
        //查询知识点
        List<KnowledgePointDto> knowledgePointDtos = topicKnowledgeCorrelationDao.selectTopicLinkedWithPoint(topic.getTopicId()).stream().map(j -> {
            KnowledgePoint knowledgePoint = topicKnowledgePointDao.selectKnowledgePointById(j);
            KnowledgePointDto knowledgePointDto = null;
            if (knowledgePoint != null) {
                knowledgePointDto = new KnowledgePointDto();
                BeanUtils.copyProperties(knowledgePoint, knowledgePointDto);
            }
            return knowledgePointDto;
        }).collect(Collectors.toList());
        topicDto.setPoints(knowledgePointDtos);
        return topicDto;
    }

    private TopicDto getTopicDto(String[] ignore, Integer i) {
        Topic topic = topicDao.selectTopicById(i);
        TopicDto topicDto = Topic2TopicDto(topic, ignore);
        //查询题目选项
        List<TopicOptionDto> topicOptionDtos = topicOptionDao.getOptionsOfTopic(i).stream().map(j -> {
            TopicOptionDto topicOptionDto = new TopicOptionDto();
            BeanUtils.copyProperties(j, topicOptionDto);
            return topicOptionDto;
        }).collect(Collectors.toList());
        topicDto.setTopicOptionDtos(topicOptionDtos);
        return topicDto;
    }

    private void addTopicSync(Vector<TopicVo> topicVos, List<Integer> errors) {
        final Integer[] i = {0};
        TokenInfoBo tokenInfoBo = AuthUserContext.get();
        Future future = new Future(i[0], topicVos, errors, tokenInfoBo,
                () -> {
                    try {
                        AuthUserContext.set(tokenInfoBo);
                        TopicHelpContext.newMap();
                        TopicVo topicVo;
                        while (i[0] < topicVos.size()) {
                            synchronized (i[0]) {
                                if (topicVos.size() <= i[0]) break;
                                topicVo = topicVos.get(i[0]);
                                System.out.println(i[0]);
                                i[0]++;
                            }
                            try {
                                TopicBo topicBo = topicVo2TopicBo(topicVo);
                                TopicKpointBo topicKpointBo = topicVo2TopicKpointBo(topicVo);
                                TopicOptionsBo topicOptionsBo = topicVo2TopicOptionsBo(topicVo);
                                addTopic(topicBo, topicKpointBo, topicOptionsBo);
                            } catch (Exception e) {
                                e.printStackTrace();
                                errors.add(i[0] + 2);
                            }
                        }
                    } finally {
                        TopicHelpContext.clear();
                        AuthUserContext.clear();
                    }
                });
        future.start();
    }

    private TopicBo topicVo2TopicBo(TopicVo topicVo) {
        TopicBo topicBo = new TopicBo();
        BeanUtils.copyProperties(topicVo, topicBo, "topicType", "topicDifficulty");
        topicBo.setTopicType(TopicTypeEnum.topicType(topicVo.getTopicType()));
        return topicBo;
    }

    private TopicKpointBo topicVo2TopicKpointBo(TopicVo topicVo) {
        TopicKpointBo topicKpointBo = new TopicKpointBo();
        topicKpointBo.setPointIds(topicVo.getPointId());
        return topicKpointBo;
    }

    private TopicOptionsBo topicVo2TopicOptionsBo(TopicVo topicVo) {
        TopicOptionsBo topicOptionsBo = new TopicOptionsBo();
        topicOptionsBo.setTopicOptions(topicVo.getTopicOptionVos());
        return topicOptionsBo;
    }
}

class Future {
    private ExecutorService pool = Executors.newFixedThreadPool(6);
    private final Integer i;
    private final Vector<TopicVo> topicVos;
    private final List<CompletableFuture<Void>> completableFutureList = new ArrayList<>();
    private final List<Integer> errors;
    private final Runnable runnable;

    public Future(Integer i, Vector<TopicVo> topicVos, List<Integer> errors, TokenInfoBo tokenInfoBo, Runnable runnable) {
        super();
        this.i = i;
        this.topicVos = topicVos;
        this.errors = errors;
        this.runnable = runnable;
    }

    public void start() {
        for (int j = 0; j < 6; j++) {
            completableFutureList.add(newOne());
        }
        CompletableFuture.allOf(completableFutureList.toArray(new CompletableFuture[0])).join();
    }

    private CompletableFuture<Void> newOne() {
        return CompletableFuture.runAsync(runnable, pool);
    }


}
